
General User Interface Tuturial for Newbies

From  BeLiAL/BCVG 2002

Introduction:

This Tuturial is part of our first e-zine. Our emperor Dr.T told me that this e-zine
hasnt to be only VX orientated so i decided to write this tute.
One year before i had to code a GUI for my Crackme but i didnt find much VXers who were able
to give me some informations about this topic. In my opinion a good coder has to be flexible 
enough to code such things (only being specialisated on virii is a weakness) so i want to share 
my informations with others. There is also a tute about GUI in the latest and last Codebreaker 
E-Zine or in IKX (shows also GUI thingies, but its a OpenGl tute). But they didnt help me much 
so here comes my version. 
All code is for MASM (only this code, all my other stuff is TASM code)!!! Yes, i know, now im a 
lamer coz im working together with the devil (m$), but i had very strange errors with TASM and MASM 
makes everything a bit easier with his ".else" and ."elseif" and all the other HLL stuff. Anyway, it 
shouldnt be very difficult to convert my code from MASM to TASM.
Okay, after this tuturial you should be able to create a simple window with a button, an EditControl and
some text. A PopUp menu and an about window is inclusive ;)

Whats GUI:

GUI (General User interface) is the switch between the user and the program. Normally its the window 
where the User can type in information (what file he want to print, which drive shall be formated), see 
whats happening and stuff like this. Microsoft provided us with many already coded GUIs (f.e. the window 
which is opend when u want to open a file with notepad), but as 31337 coderz ;) we should be able to code our own one. 

Needed things:

For understanding this Tute u have to know a little bit about win32asm, thats all. The rest is explained by me. 
The only software u need is the Microsoft Macro Assembler. U can get it with the DDK on msdn.microsoft.com .

How does windows handle all his windows:

Windows is multitasking, a fact u shouldnt forget. When a program like notepad is started it creates his windows(s) 
and waits for the commands of the user. This waiting for commands is an endless loop in which APIs like GetMessage() 
and DispatchMessage() are used. 

-> note to Messages in Windows: If something is happening in windows (a key was pressed, the mouse is moving...), 
   it sends messages to his programs.

This message loop checks wether one of the incoming messages is important for the program. If its a message 
for the program (f.e. one of the popups in notepad was klicked), it switches to WinProc(). There the the program 
checks what exactly happend ( was it copy/paste or exit or the infobutton in popup Options f.e.). This WinProc 
function is called Callback-function and it handles all messages which are important for our program. So our 
program can be devided into three parts:

1. Create the window (which size, colour, x and y coordinates etc...)
2. MessageLoop (is something happening in windows which is important for our program?)
3. WinProc (somethings happend, but what and what to do)

Very easy, isnt it?
 
But how can we use things like Buttons or EditControls (the place where the user can enter some text)? Thats easy
too. All these things are handled like windows too. After the main window is created, the program creates the button
with the same API which created the main window. The only difference is that we use now the WS_CHILD parameter, because
the button is a "child of the main window".  

the rc file:

The .asm file of the program is not the only thing we need. There is also a resource-file. It looks like this:

#define IDM_GOODBYE 2
#define IDM_ABOUT 3

GUIexample MENU
{
 POPUP "&Exit"
        {
         MENUITEM "&Quit", IDM_GOODBYE
        }
 POPUP "&About"
        {
         MENUITEM "&About",IDM_ABOUT
        } 
}

I think its quite selfexplanatory. The two menus are defined there. One menu has the name Exit and one About. The "&" before
them defines the hotkey. IDM_GOODBYE represent the message number, so that windows know which popup was clicked by the
user. IDM_GOODBYE and IDM_ABOUT have to be defined in the asm-file too. The Menuname "GUIexample" is also represented
in the asm-file and has to have the same name (in our case "GUIexample").

gui.asm :

I will explain and comment all neccessary things, but not the whole file. So if u  want more detail and the whole example code,
take a look into gui.asm.
Here we go:

invoke GetModuleHandle,NULL
mov hInstance,eax

invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT 
  
invoke ExitProcess,eax

First, our program gets a handle, which is needed for the future. Then it calls WinMain(), which is the the whole program. When
this function is finished (which means, the program was terminated), ExitProcess quits the program.

mov   wc.cbSize,SIZEOF WNDCLASSEX
mov   wc.style, CS_HREDRAW or CS_VREDRAW 
mov   wc.lpfnWndProc, offset WinProc
mov   wc.cbClsExtra,NULL 
mov   wc.cbWndExtra,NULL 
mov   eax,hInstance
mov   wc.hInstance,eax

Later in the program, a function named RegisterClass() is called. This API is needed to register a class for the function CreateWindow(),
which is elementary for the program. RegisterClass() needs a structure called WNDCLASSEX. And the variables of this structure are
filled with these code lines. Also the modulehandle above is used in this structure. wc.style defines the style of the class. CS_HREDRAW
and CS_VREDRAW say that the window of the program is repainted when the window is moved. wc.lpfnWndProc gets the address of WinProc.
cbClsExtra specifies the number of extra bytes to allocate following the window-class structure. The operating system initializes 
the bytes to zero. cbWndExtra specifies the number of extra bytes to allocate following the window instance. The operating system 
initializes the bytes to zero. If an application uses the WNDCLASS structure to register a dialog box created by using the CLASS 
directive in the resource file, it must set this member to DLGWINDOWEXTRA.

invoke LoadIcon,NULL,IDI_APPLICATION
mov   wc.hIcon,eax
mov   wc.hIconSm,eax 

invoke LoadCursor,NULL,IDC_ARROW	
mov    wc.hCursor,eax

The windowclass needs also an icon and a cursor. These parameters have to be initialised with the APIs LoadCorsor() and LoadIcon().

mov   wc.hbrBackground,2 
mov   wc.lpszMenuName,OFFSET themenu
mov   wc.lpszClassName,OFFSET classname 
invoke RegisterClassEx, addr wc

The backgroundvalue defines the colour of the window. I took 2, but change it toi whatever u want. lpszMenuName gives the name of
the PopUpMenu. It has to be equal to the value in the rc file. The classname is up to your choice.
Now, all needed informations are there and RegisterClass() can be called.

invoke CreateWindowEx,NULL,addr classname,addr appname,00cf0000h,\
                      CW_USEDEFAULT,CW_USEDEFAULT,200,140,\
                      NULL,NULL,hInst,NULL
mov   hwnd,eax 

invoke ShGetMessage does not retrieve messages for windows that belong to other threads or applications. owWindow, hwnd,CmdShow 
invoke UpdateWindow, hwnd 

These are the last parts before we enter the message loop, i talked about at the beginning of the tuturial. CreateWindowEx() creates the
window and returns a handle. This handle is needed in WinProc() when child windows are created. The following values are pushed
for the function:

DWORD  dwExStyle,	// extended window style
    LPCTSTR  lpszClassName,	// address of registered class name
    LPCTSTR  lpszWindowName,	// address of window name
    DWORD  dwStyle,	// window style
    int  x,	// horizontal position of window
    int  y,	// vertical position of window
    int  nWidth,	// window width
    int  nHeight,	// window height
    HWND  hwndParent,	// handle of parent or owner window
    HMENU  hmenu,	// handle of menu, or child-window identifier
    HINSTANCE  hinst,	// handle of application instance
    LPVOID  lpvParam 	// address of window-creation data

As u see, many of them are not important and are zero. classname and appname have to be equal to the values in the WNDCLASSEX structure.
For overlapped windows, nWidth is the window's width, in screen coordinates, or CW_USEDEFAULT. If nWidth is CW_USEDEFAULT, Windows 
selects a default width and height for the window; the default width extends from the initial x-coordinates to the right edge of the 
screen; the default height extends from the initial y-coordinate to the top of the icon area. 
The ShowWindow function sets the specified window's show state. the first parameter is is the window handle. The second says how the
the window has to be shown. In our case CmdShow activates the window and displays it on the screen. UpdateWindow() updates the client
area of the window. It sends a WM_PAINT message to the program. This message is explained later. For you it is only important to know,
that because of this message, the child windows will be created too.  

 .WHILE TRUE 
                invoke GetMessage, ADDR msg,NULL,0,0 
                .BREAK .IF (!eax) 
                invoke TranslateMessage, ADDR msg 
                invoke DispatchMessage, ADDR msg 
 .ENDW
 
mov     eax,msg.wParam 
ret                         

What u see here is the message loop. It runs and runs until the user quits his program. When done so, it will leave the function WinMain()
(u see the "ret" ?) and quit the program with ExitProcess. The parameter for ExitProcess() is the last message.
With GetMessage() a message is copied from the message queue to the structure "msg". GetMessage does not retrieve messages for windows that 
belong to other threads or applications. The TranslateMessage function translates virtual-key messages into character messages. The character 
messages are posted to the calling thread's message queue, to be read the next time the thread calls the GetMessage or PeekMessage function.
The DispatchMessage function dispatches a message to a window procedure. Its very important that u use these three APIs. Believe me, if u dont
do so, ur code will fail with some curious errors.
Now its time to take a little look at our WinProc() part of the program. It uses some structures, created with the LOCAL command of Masm.
In this procedure, our program checks what a message was given to him and what to do now. If a message is there, with no importance (f.e. if
the user simply clicks on our window), the message is given to DefWindowProc(). But before i explain more, here is some code:

.IF uMsg==WM_DESTROY                         
        invoke PostQuitMessage,NULL
        
 .ELSEIF uMsg==WM_PAINT
        invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR editclass,NULL,\ 
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\ 
                        ES_AUTOHSCROLL,\ 
                        0,24,90,20,hWnd,8,hInstance,NULL
        mov edithandle,eax

        invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                        0,50,40,20,hWnd,ButtonID,hInstance,NULL
        mov  hwndButton,eax
                 
        invoke BeginPaint,hWnd, addr ps 
        mov    hdc,eax 
        invoke GetClientRect,hWnd, addr rect
        mov rect.right,170       
        invoke DrawText, hdc,addr wintext,-1, ADDR rect, \ 
                     DT_SINGLELINE  
        invoke EndPaint,hWnd, addr ps 

Hey, its more easier than it may look to you. There are a few important happenings (messages) for the program. WM_DESTROY is sended
when the user quits the program. If so, a quit message is send via PostQuitMessage(). The other poissibilty is is a WM_PAINT message.
This message appears if the window has to be painted or repainted. For example, if the user moves to winow from the upper left corner
of his screen to the upper right. Now the window is repainted with BeginPaint() and EndPaint(). All the other parts of the main
window, like child windows or some simple text have to be recreated too, so its important to put the neccessary routines in this place.
As you see, the button f.e. is created with CreateWindow() too, but with the parameter WS_CHILD. And it gets an ID, in our case ButtonId.
This ID is important in WM_COMMAND.The GetClientRect() function retrieves the coordinates of a window's client area. The client 
coordinates specify the upper-left and lower-right corners of the client area. With DrawText, a simple text is created on the main window.

.ELSEIF uMsg==WM_COMMAND 
        mov eax,wParam
   .IF lParam==0    
     .IF ax==IDM_ABOUT
        invoke MessageBox,NULL,offset text2,offset text1, MB_OK 
     .ELSE   
        invoke DestroyWindow,hWnd
     .ENDIF
   .ELSE 
     .IF ax==EDITID
        shr eax,16
     .ENDIF                         
   .ENDIF

The WM_COMMAND part is important when a button was clicked, a popup menu was used etc...The program checks firstly for the PopUps. When
IDM_ABOUT was clicked a messagebox appears. If the other popup was used (the exit button) the program quits. As u can see, u can put
there also the code which tells the program what to to when a button is clicked. Simply put an .IF with the buttonid there if u want to
use ur button.

.ELSE 
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam   
        ret
.ENDIF

This is the default message handling i spoke about a bit earlier. Now, the most important things are explained and i hope you will code
some nice windows ;). For any suggestions, send me a mail. 